using Microsoft.Expression.Drawing.Core;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Microsoft.Expression.Controls
{
	public sealed class PathPanel : Panel
	{
		private const double SmoothNormalRange = 10.0;
		private static readonly Rect ZeroRect = new Rect(0.0, 0.0, 0.0, 0.0);
		private static readonly Size InfinteSize = new Size(double.PositiveInfinity, double.PositiveInfinity);
		private static readonly Vector Up = new Vector(0.0, -1.0);
		private Point lastPoint;
		private double totalLength;
		private double previousLength;
		private bool shouldLayoutHiddenChildren;
		private bool isListening;
		private bool isUnloaded;
		private int[] indices;
		public static readonly DependencyProperty LayoutPathsProperty = DependencyProperty.Register("LayoutPaths", typeof(LayoutPathCollection), typeof(PathPanel), new PropertyMetadata(null, new PropertyChangedCallback(PathPanel.LayoutPropertyChanged)));
		public static readonly DependencyProperty StartItemIndexProperty = DependencyProperty.Register("StartItemIndex", typeof(double), typeof(PathPanel), new PropertyMetadata(0.0, new PropertyChangedCallback(PathPanel.LayoutPropertyChanged)));
		public static readonly DependencyProperty WrapItemsProperty = DependencyProperty.Register("WrapItems", typeof(bool), typeof(PathPanel), new PropertyMetadata(false, new PropertyChangedCallback(PathPanel.LayoutPropertyChanged)));
		public LayoutPathCollection LayoutPaths
		{
			get
			{
				return (LayoutPathCollection)base.GetValue(PathPanel.LayoutPathsProperty);
			}
			set
			{
				base.SetValue(PathPanel.LayoutPathsProperty, value);
			}
		}
		public double StartItemIndex
		{
			get
			{
				return (double)base.GetValue(PathPanel.StartItemIndexProperty);
			}
			set
			{
				base.SetValue(PathPanel.StartItemIndexProperty, value);
			}
		}
		public bool WrapItems
		{
			get
			{
				return (bool)base.GetValue(PathPanel.WrapItemsProperty);
			}
			set
			{
				base.SetValue(PathPanel.WrapItemsProperty, value);
			}
		}
		internal IList<LayoutPath> ValidPaths
		{
			get;
			private set;
		}
		internal int Count
		{
			get
			{
				if (this.indices == null)
				{
					return 0;
				}
				return this.indices.Length;
			}
		}
		public PathPanel()
		{
			LayoutPathCollection layoutPathCollection = new LayoutPathCollection();
			base.SetValue(PathPanel.LayoutPathsProperty, layoutPathCollection);
			base.add_Loaded(new RoutedEventHandler(this.PathPanel_Loaded));
			base.add_Unloaded(new RoutedEventHandler(this.PathPanel_Unloaded));
		}
		protected override Size MeasureOverride(Size availableSize)
		{
			using (IEnumerator<UIElement> enumerator = base.get_Children().GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					UIElement current = enumerator.get_Current();
					if (current != null)
					{
						current.Measure(PathPanel.InfinteSize);
					}
				}
			}
			return base.MeasureOverride(availableSize);
		}
		protected override Size ArrangeOverride(Size finalSize)
		{
			Size result = base.ArrangeOverride(finalSize);
			if (this.LayoutPaths != null && this.LayoutPaths.get_Count() > 0)
			{
				using (IEnumerator<LayoutPath> enumerator = this.LayoutPaths.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						LayoutPath current = enumerator.get_Current();
						if (!current.IsAttached)
						{
							current.Attach(this);
						}
					}
				}
				this.ValidPaths = new List<LayoutPath>(Enumerable.Where<LayoutPath>(this.LayoutPaths, (LayoutPath path) => path.IsAttached && path.SourceElement.get_Visibility() != 1));
			}
			else
			{
				this.ValidPaths = null;
			}
			if (base.get_Children().get_Count() == 0)
			{
				return result;
			}
			if (this.ValidPaths == null || this.ValidPaths.get_Count() == 0)
			{
				this.ArrangeFirstChild();
				return result;
			}
			if (!this.UpdateIndirection())
			{
				return result;
			}
			this.lastPoint = default(Point);
			this.previousLength = 0.0;
			using (IEnumerator<LayoutPath> enumerator2 = this.ValidPaths.GetEnumerator())
			{
				while (enumerator2.MoveNext())
				{
					LayoutPath current2 = enumerator2.get_Current();
					current2.UpdateCache();
				}
			}
			this.totalLength = 0.0;
			using (IEnumerator<LayoutPath> enumerator3 = this.ValidPaths.GetEnumerator())
			{
				while (enumerator3.MoveNext())
				{
					LayoutPath current3 = enumerator3.get_Current();
					this.totalLength += current3.TotalLength;
				}
			}
			int i = 0;
			int num = 0;
			while (num < this.LayoutPaths.get_Count() && i < this.Count)
			{
				LayoutPath layoutPath = this.LayoutPaths.get_Item(num);
				if (layoutPath.IsAttached && layoutPath.SourceElement.get_Visibility() != 1)
				{
					i = layoutPath.Distribute(num, i);
					this.previousLength += layoutPath.TotalLength;
				}
				num++;
			}
			while (i < this.Count)
			{
				UIElement hiddenChild = base.get_Children().get_Item(this.indices[i]);
				PathPanel.HideAtPoint(hiddenChild, this.lastPoint);
				i++;
			}
			return result;
		}
		internal void ArrangeChild(int indirectIndex, int pathIndex, PolylineData polyline, MarchLocation location, int localIndex)
		{
			LayoutPath layoutPath = this.LayoutPaths.get_Item(pathIndex);
			int num = this.indices[indirectIndex];
			UIElement uIElement = base.get_Children().get_Item(num);
			this.lastPoint = location.GetPoint(polyline.Points);
			if (this.shouldLayoutHiddenChildren)
			{
				int num2 = Math.Min(base.get_Children().get_Count(), Math.Max(0, (int)Math.Round(this.StartItemIndex)));
				for (int i = 0; i < num2; i++)
				{
					PathPanel.HideAtPoint(base.get_Children().get_Item(i), this.lastPoint);
				}
				this.shouldLayoutHiddenChildren = false;
			}
			IPathLayoutItem pathLayoutItem = uIElement as IPathLayoutItem;
			if (pathLayoutItem != null)
			{
				Vector vector = -location.GetNormal(polyline, 10.0);
				double num3 = Vector.AngleBetween(PathPanel.Up, vector);
				double lengthTo = layoutPath.GetLengthTo(polyline, location);
				double rhs = layoutPath.TotalLength;
				pathLayoutItem.Update(new PathLayoutData
				{
					LayoutPathIndex = pathIndex,
					GlobalIndex = num,
					LocalIndex = localIndex,
					NormalAngle = num3,
					OrientationAngle = (layoutPath.Orientation == Orientation.OrientToPath) ? num3 : 0.0,
					LocalOffset = MathHelper.SafeDivide(lengthTo, rhs, 0.0),
					GlobalOffset = MathHelper.SafeDivide(this.previousLength + lengthTo, this.totalLength, 0.0),
					IsArranged = true
				});
			}
			Rect rect = new Rect(this.lastPoint, default(Size));
			double num4 = uIElement.get_DesiredSize().get_Width() / 2.0;
			double num5 = uIElement.get_DesiredSize().get_Height() / 2.0;
			rect = GeometryHelper.Inflate(rect, new Thickness(num4, num5, num4, num5));
			uIElement.Arrange(rect);
		}
		internal double GetChildRadius(int indirectIndex)
		{
			UIElement uIElement = base.get_Children().get_Item(this.indices[indirectIndex]);
			return Math.Max(uIElement.get_DesiredSize().get_Width(), uIElement.get_DesiredSize().get_Height()) / 2.0;
		}
		private bool UpdateIndirection()
		{
			int num = base.get_Children().get_Count();
			int num2 = Math.Max(0, (int)Math.Round(this.StartItemIndex));
			if (!this.WrapItems)
			{
				num2 = Math.Min(num, num2);
				num -= num2;
				if (num <= 0)
				{
					using (IEnumerator<UIElement> enumerator = base.get_Children().GetEnumerator())
					{
						while (enumerator.MoveNext())
						{
							UIElement current = enumerator.get_Current();
							current.Arrange(PathPanel.ZeroRect);
							PathPanel.RemovePathLayoutProperties(current as PathListBoxItem, false);
						}
					}
					return false;
				}
				this.shouldLayoutHiddenChildren = true;
			}
			else
			{
				num2 %= num;
			}
			if (this.indices == null || this.indices.Length != num)
			{
				this.indices = new int[num];
				int num3 = num2;
				for (int i = 0; i < num; i++)
				{
					this.indices[i] = num3;
					num3 = (num3 + 1) % base.get_Children().get_Count();
				}
			}
			return true;
		}
		private static void HideAtPoint(UIElement hiddenChild, Point point)
		{
			Point point2 = point.Minus(new Point(hiddenChild.get_DesiredSize().get_Width() / 2.0, hiddenChild.get_DesiredSize().get_Height() / 2.0));
			PathPanel.RemovePathLayoutProperties(hiddenChild as PathListBoxItem, false);
			hiddenChild.Arrange(new Rect(point2, new Size(0.0, 0.0)));
		}
		private void ArrangeFirstChild()
		{
			UIElement uIElement = base.get_Children().get_Item(0);
			uIElement.Arrange(new Rect(default(Point), base.get_Children().get_Item(0).get_DesiredSize()));
			PathPanel.RemovePathLayoutProperties(uIElement as PathListBoxItem, true);
			for (int i = 1; i < base.get_Children().get_Count(); i++)
			{
				UIElement uIElement2 = base.get_Children().get_Item(i);
				uIElement2.Arrange(PathPanel.ZeroRect);
				PathPanel.RemovePathLayoutProperties(uIElement2 as PathListBoxItem, false);
			}
		}
		private void PathPanel_Loaded(object sender, RoutedEventArgs e)
		{
			base.InvalidateArrange();
		}
		private void PathPanel_Unloaded(object sender, RoutedEventArgs e)
		{
			CompositionTarget.remove_Rendering(new EventHandler(this.CheckOnRenderHandler));
			base.remove_LayoutUpdated(new EventHandler(this.CheckOnLayoutHandler));
			this.isListening = false;
			this.isUnloaded = true;
		}
		private static void LayoutPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{
			PathPanel pathPanel = d as PathPanel;
			if (pathPanel == null)
			{
				return;
			}
			if (e.get_Property() != PathPanel.StartItemIndexProperty)
			{
				if (e.get_Property() != PathPanel.WrapItemsProperty)
				{
					if (e.get_Property() != PathPanel.LayoutPathsProperty)
					{
						goto IL_107;
					}
					if (e.get_NewValue() == e.get_OldValue())
					{
						return;
					}
					LayoutPathCollection layoutPathCollection = e.get_OldValue() as LayoutPathCollection;
					if (layoutPathCollection != null)
					{
						using (IEnumerator<LayoutPath> enumerator = layoutPathCollection.GetEnumerator())
						{
							while (enumerator.MoveNext())
							{
								LayoutPath current = enumerator.get_Current();
								current.Detach();
							}
						}
						layoutPathCollection.remove_CollectionChanged(new NotifyCollectionChangedEventHandler(pathPanel.LayoutPaths_CollectionChanged));
					}
					LayoutPathCollection layoutPathCollection2 = e.get_NewValue() as LayoutPathCollection;
					if (layoutPathCollection2 != null)
					{
						using (IEnumerator<LayoutPath> enumerator2 = layoutPathCollection2.GetEnumerator())
						{
							while (enumerator2.MoveNext())
							{
								LayoutPath current2 = enumerator2.get_Current();
								current2.Attach(pathPanel);
							}
						}
						layoutPathCollection2.add_CollectionChanged(new NotifyCollectionChangedEventHandler(pathPanel.LayoutPaths_CollectionChanged));
					}
					PathPanel.UpdateListeners(pathPanel);
					goto IL_107;
				}
			}
			pathPanel.indices = null;
			IL_107:
			pathPanel.InvalidateArrange();
		}
		private void LayoutPaths_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			bool flag = false;
			if (e.get_OldItems() != null)
			{
				IEnumerator enumerator = e.get_OldItems().GetEnumerator();
				try
				{
					while (enumerator.MoveNext())
					{
						LayoutPath layoutPath = (LayoutPath)enumerator.get_Current();
						layoutPath.Detach();
						flag = true;
					}
				}
				finally
				{
					IDisposable disposable = enumerator as IDisposable;
					if (disposable != null)
					{
						disposable.Dispose();
					}
				}
			}
			if (e.get_NewItems() != null)
			{
				IEnumerator enumerator2 = e.get_NewItems().GetEnumerator();
				try
				{
					while (enumerator2.MoveNext())
					{
						LayoutPath layoutPath2 = (LayoutPath)enumerator2.get_Current();
						layoutPath2.Attach(this);
						flag = true;
					}
				}
				finally
				{
					IDisposable disposable2 = enumerator2 as IDisposable;
					if (disposable2 != null)
					{
						disposable2.Dispose();
					}
				}
			}
			if (flag)
			{
				PathPanel.UpdateListeners(this);
				base.InvalidateArrange();
			}
		}
		private static void UpdateListeners(PathPanel pathPanel)
		{
			if (pathPanel.isUnloaded)
			{
				return;
			}
			bool flag = pathPanel.LayoutPaths != null && pathPanel.LayoutPaths.get_Count() > 0;
			if (!pathPanel.isListening && flag)
			{
				CompositionTarget.add_Rendering(new EventHandler(pathPanel.CheckOnRenderHandler));
				pathPanel.add_LayoutUpdated(new EventHandler(pathPanel.CheckOnLayoutHandler));
				pathPanel.isListening = true;
				return;
			}
			if (pathPanel.isListening && !flag)
			{
				CompositionTarget.remove_Rendering(new EventHandler(pathPanel.CheckOnRenderHandler));
				pathPanel.remove_LayoutUpdated(new EventHandler(pathPanel.CheckOnLayoutHandler));
				pathPanel.isListening = false;
			}
		}
		private void CheckOnRenderHandler(object sender, EventArgs e)
		{
			if (this.LayoutPaths != null && this.LayoutPaths.get_Count() != 0)
			{
				using (IEnumerator<LayoutPath> enumerator = this.LayoutPaths.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						LayoutPath current = enumerator.get_Current();
						if (current.IsAttached)
						{
							current.CheckRenderState();
						}
					}
				}
				return;
			}
		}
		private void CheckOnLayoutHandler(object sender, EventArgs e)
		{
			if (this.LayoutPaths != null && this.LayoutPaths.get_Count() != 0)
			{
				using (IEnumerator<LayoutPath> enumerator = this.LayoutPaths.GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						LayoutPath current = enumerator.get_Current();
						if (current.IsAttached)
						{
							current.CheckLayoutState();
						}
					}
				}
				return;
			}
		}
		private static void RemovePathLayoutProperties(IPathLayoutItem pathLayoutItem, bool isArranged = false)
		{
			if (pathLayoutItem == null)
			{
				return;
			}
			pathLayoutItem.Update(new PathLayoutData
			{
				LayoutPathIndex = 0,
				GlobalIndex = 0,
				LocalIndex = 0,
				NormalAngle = 0.0,
				OrientationAngle = 0.0,
				LocalOffset = 0.0,
				GlobalOffset = 0.0,
				IsArranged = isArranged
			});
		}
	}
}
